import { Mouse } from "./behavior/Mouse";
import { any } from "../../core/logic";
import { Component, ComponentType } from "../Component";
import { Engine } from "../../Engine";
import { Pass } from "../post/Pass";
import { ids } from "../../core/ids";
import { debounce } from "../../core/fun";
/**
 * 轨道控制器类
 * @class
 * @memberof w.control
 */
class Pick extends Component {
    /**
     * @constructor
     * @param opts {object}
     * @param opts.action {String} 【可选，缺省:"click"】拾取的交互行为,"click"|"mousemove"。
     */
    constructor(opts = {}) {
        opts.type = ComponentType.Pick;
        super(opts);
        this.callbacks = {
            "click": [],
            "mousemove": []
        }
        this._action = any(opts.action, ["click"]);
        //创建一个像素的数据
        this.initPixelBuffer();
        this.mouseBehavior = new Mouse(opts);
        this.mouseBehavior.active();
        this.active();
    }
    initPixelBuffer() {
        this.colorBuffer = Engine.instance.device.createBuffer({
            size: 4,
            usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
        });
        this.positionBuffer = Engine.instance.device.createBuffer({
            size: 16,
            usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
        });

    }
    set action(v) {
        this._action = v;
        this.deactive();
        this.active();
    }
    get action() {
        return this._action;
    }
    async pick(e) {
        Engine.instance.scene.orbit.stopAnimation();
        if (!Engine.instance.enablePick) {//如果为开启拾取则不执行拾取
            return;
        }
        if (e.type == "mousemove" && e.originEvent.buttons != 0) {//按住鼠标移动不进行拾取
            return;
        }
        if (this.inPick) {
            return;
        }
        this.inPick = true;
        const callbacks = this.callbacks[e.type];
        let pixel = e.data.pixel;
        pixel[0] = Math.ceil(pixel[0]);
        pixel[1] = Math.ceil(pixel[1]);
        //执行拾取
        if (this.colorBuffer.mapState != "unmapped" || this.positionBuffer.mapState != "unmapped") {
            this.inPick = false;
            return;
        }
        let { mesh, worldposition } = await this.readPixel(pixel);
        let instanceIndex, entity;
        if (mesh) {
            let eid = [...mesh.eids][0];
            if (eid) {
                let e = Engine.instance.register.entityManager.get(eid);
                if (e) {
                    entity = e;
                }
            }
            let instance = entity.trans;
            if (instance.hash == "transinstance") {//如果是实例化则找出具体的实例。
                let dismin = Number.MAX_VALUE, index = 0;
                for (let i = 0; i < instance.instanceCount; i++) {
                    let trans = instance.getInstance(i);
                    let dis = trans.dis(worldposition);
                    if (dis < dismin) {
                        dismin = dis;
                        index = i;
                    }
                }
                instanceIndex = index;
            }
        }
        //执行Script脚本。
        let he = entity;
        while (he) {
            let scriptCom = he.script;
            if (scriptCom) {
                if (e.type == scriptCom.behavior) {
                    he.worldposition=worldposition;
                    he.pixel=pixel;
                    he.instanceIndex=instanceIndex;
                    scriptCom.onScript(he);
                }
            }
            he = he.parent;
        }
        //全局执行
        for (let i = 0; i < callbacks.length; i++) {
            callbacks[i]({ mesh, pixel, worldposition, entity, instanceIndex, event: e });
        }
        this.inPick = false;
    }
    async readPixel(origin) {
        let mesh;
        // 创建一个命令缓冲区
        const commandEncoder = Engine.instance.device.createCommandEncoder();
        // 设置拷贝操作的源和目标
        const colorView = {
            texture: Pass.instance().pickAttach,
            origin
        };
        const colorBufferView = {
            buffer: this.colorBuffer,
            bytesPerRow: 256, // 每行的字节数
            rowsPerImage: 1, // 每张图片的行数
        }
        // 将纹理数据拷贝到缓冲区
        commandEncoder.copyTextureToBuffer(colorView, colorBufferView, [1, 1]);
        if (Engine.instance.enableGbuffer) {
            const positionView = {
                texture: Pass.instance().postionTexture,
                origin
            };
            const positionBufferView = {
                buffer: this.positionBuffer,
                bytesPerRow: 256, // 每行的字节数
                rowsPerImage: 1, // 每张图片的行数
            }
            // 将纹理数据拷贝到缓冲区
            commandEncoder.copyTextureToBuffer(positionView, positionBufferView, [1, 1]);
        }
        // 提交命令并等待执行完成
        const commandBuffer = commandEncoder.finish();
        await Engine.instance.device.queue.submit([commandBuffer]);
        // 使用 mapReadAsync 从缓冲区中读取像素数据
        await this.colorBuffer.mapAsync(GPUMapMode.READ);
        // 获取像素数据
        let color = new Uint8Array(this.colorBuffer.getMappedRange());
        let id = ids.fromColor(color);
        if (id === "0") {
            color = null;
            this.colorBuffer.unmap();
        } else {
            mesh = Engine.instance.register.manager(ComponentType.Mesh).get(id);
            this.colorBuffer.unmap();
        }
        //获取世界坐标
        let worldposition;
        if (Engine.instance.enableGbuffer) {
            await this.positionBuffer.mapAsync(GPUMapMode.READ);
            let position = new Float32Array(this.positionBuffer.getMappedRange());
            worldposition = [position[0], position[1], position[2]];
            this.positionBuffer.unmap();
        } else {
            worldposition = Engine.instance.scene.getCamera().pixelToWorld(origin).toArray();
        }
        return { mesh, worldposition };
    }
    active() {
        super.active();
        for (let i = 0; i < this.action.length; i++) {
            this.on(this.action[i], this.pick);
        }
    }
    /**
     * 拾取控制器注销。
     * @method
     */
    deactive() {
        for (let i = 0; i < this.action.length; i++) {
            this.off(this.action[i], this.pick);
        }
    }
    /**
     * @param {*} callback 
     * @param {*} type "click","mousemove"
     */
    select(callback, type = "click") {
        let index = this.callbacks[type].indexOf(callback);
        if (index === -1) {
            this.callbacks[type].push(callback);
        }

    }
    offSelect(callback, type = "click") {
        if (!callback) {
            this.callbacks[type] = [];
            return;
        }
        let index = this.callbacks[type].indexOf(callback);
        if (index >= 0) {
            this.callbacks[type].splice(index, 1);
        }
    }
}
export { Pick }